
/**
 * @file:       point_container.hpp
 * @author:     WubinWang
 * @contact:    wubinstu@163.com
 * @date:       2025-01-01
 * @license:    MIT License
 *
 * Copyright (c) 2025 WubinWang
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * DISCLAIMER:
 * 1. User acknowledges all application risks and consequences arising from usage
 *    of this software are exclusively borne by the user.
 * 2. The original author shall not be held liable for any direct, indirect,
 *    incidental, special, exemplary or consequential damages.
 * 3. No warranty of fitness for particular purpose or non-infringement is provided. */


#ifndef __POINT_CONTAINER_POOL_HPP_
#define __POINT_CONTAINER_POOL_HPP_

#include <cstdint>
#include <list>
#include <memory>
#include <unordered_map>
#include <vector>

constexpr const static inline auto POINT_NO_MIN = 0;

/// @brief 点类型的基本型
/// @details 包含了点的编号并默认构造为 POINT_NO_MIN, 重写了基于编号的比较大小和加减运算符, 删除了后置自增/减运算符
/// @attention 该类型是一个抽象类型, 使用了原型模式, 其派生类应该重写 clone 函数, 比如:
///     struct MyPoint : public Point_Base_st {
///         POINT_METHOD_CLONE_IMPLEMENT (MyPoint)  // 使用宏定义快速重写 clone 函数
///     };
///
/// 另外 clone 函数一定程度依赖于对应的复制构造函数, 如果派生类的实现中使用了动态内存等其他资源并需要进行深拷贝
/// 则派生类应该手动重写符合要求的复制构造函数, 比如:
///     struct MyPoint : public Point_Base_st {
///         POINT_METHOD_CLONE_IMPLEMENT (MyPoint)
///         MyPoint (const MyPoint & _other) {  // 手动实现深拷贝
///             this->mem = new std::uint8_t[50];
///             std::memcpy (this->mem, _other.mem, 50);
///         }
///       private:
///         std::uint8_t * mem {nullptr};
///     };
struct Point_Base_st {

    virtual ~Point_Base_st () noexcept = default;
    explicit Point_Base_st (std::uint16_t no = POINT_NO_MIN) noexcept :
        _no {no} {}


    virtual inline auto clone () const -> std::unique_ptr<Point_Base_st> = 0;
    #define POINT_METHOD_CLONE_IMPLEMENT(POINT_TYPE) virtual inline auto clone () const -> std::unique_ptr<Point_Base_st> override { return std::make_unique<POINT_TYPE> (static_cast<const POINT_TYPE &> (*this)); }


    virtual inline auto operator<  (const Point_Base_st & _p) const noexcept -> bool { return this->_no < _p._no; }
    virtual inline auto operator<= (const Point_Base_st & _p) const noexcept -> bool { return this->_no <= _p._no; }
    virtual inline auto operator== (const Point_Base_st & _p) const noexcept -> bool { return this->_no == _p._no; }
    virtual inline auto operator>= (const Point_Base_st & _p) const noexcept -> bool { return this->_no >= _p._no; }
    virtual inline auto operator>  (const Point_Base_st & _p) const noexcept -> bool { return this->_no > _p._no; }

    virtual inline auto operator++ () noexcept -> Point_Base_st & { ++this->_no; return *this; }
    virtual inline auto operator-- () noexcept -> Point_Base_st & { --this->_no; return *this; }

    virtual inline auto operator++ (int) noexcept -> Point_Base_st = delete;
    virtual inline auto operator-- (int) noexcept -> Point_Base_st = delete;

    virtual inline auto operator+ (std::uint16_t _step) const noexcept -> std::uint16_t { return 0xFFFFU & static_cast<std::uint16_t> (this->_no + _step); }
    virtual inline auto operator- (std::uint16_t _step) const noexcept -> std::uint16_t { return 0xFFFFU & static_cast<std::uint16_t> (this->_no - _step); }

    std::uint16_t _no;  // 点的编号
};

/// @brief 使用 STL 容器存储 Point_Base_st 并保持多态特性
/// 该类实现了 Point_Base_st 多态对象的增删改查, 并始终按照 Point_Base_st::_no 从小到大的顺序保持列表有序
class Linear_Container_ct {
  public:

    explicit Linear_Container_ct () noexcept = default;
    virtual ~Linear_Container_ct () noexcept = default;
    explicit Linear_Container_ct (const Linear_Container_ct & _other) noexcept;
    explicit Linear_Container_ct (Linear_Container_ct && _other) noexcept;
    Linear_Container_ct & operator= (const Linear_Container_ct & _other) noexcept;
    Linear_Container_ct & operator= (Linear_Container_ct && _other) noexcept;

    // 自定义构造函数
    explicit Linear_Container_ct (std::uint16_t _line_id) noexcept;

    /// @brief 初始化, 清空表
    /// @param _id 重设的线的ID
    virtual auto init (std::uint16_t _id = 0) -> void;


    /// @brief 返回点数量
    virtual auto counts () -> std::uint16_t;


    /// @brief 返回线 ID
    virtual auto id () -> std::uint16_t &;


    /// @brief 获取指定编号的点
    /// @param _no 点编号, 需要确保点编号的合法性
    /// @param _pb 输出参数, 返回点的地址, 默认 nullptr, 即不从参数输出, 而从返回值获取
    /// @return 返回点的地址, 如果查找失败则返回空指针
    virtual auto get (std::uint16_t _no, Point_Base_st ** _pb = nullptr) -> Point_Base_st *;


    /// @brief 将点追加到表末尾 (总点数会增加一个, 会自动检查和修改当前最后一个点的编号和新追加的点编号的连续性)
    /// @param _pb 被追加的点
    virtual auto append (const Point_Base_st & _pb) -> void;


    /// @brief 在指定位置插入点 (总点数会增加一个, 插入位置之后的点编号会自动自增一个单位)
    /// @param _no 被插入(取代后移)的点编号
    /// @param _pb 被插入的点, 该点的编号会被自动设置为参数 _no
    virtual auto insert (std::uint16_t _no, const Point_Base_st & _pb) -> void;


    /// @brief 替换指定位置的点 (总点数保持不变, 其余点的编号不会更新)
    /// @param _no 被替换(取代)的点编号
    /// @param _pb 替换的点, 该点的编号会被自动设置为参数 _no
    virtual auto replace (std::uint16_t _no, const Point_Base_st & _pb) -> void;


    /// @brief 删除指定位置的点 (总点数量减少一个, 删除位置之后的点编号会自动自减一个单位)
    /// @param _no 被删除的点编号
    virtual auto remove (std::uint16_t _no) -> void;


  private:
    std::uint16_t                             _m_line_id;
    std::list<std::unique_ptr<Point_Base_st>> _m_line_list;
};

class MultiLinear_Container_ct {

  public:

    explicit MultiLinear_Container_ct () noexcept                                           = default;
    virtual ~MultiLinear_Container_ct () noexcept                                           = default;
    explicit MultiLinear_Container_ct (const MultiLinear_Container_ct & _other) noexcept    = delete;
    explicit MultiLinear_Container_ct (MultiLinear_Container_ct && _other) noexcept         = delete;
    MultiLinear_Container_ct & operator= (const MultiLinear_Container_ct & _other) noexcept = delete;
    MultiLinear_Container_ct & operator= (MultiLinear_Container_ct && _other) noexcept      = delete;


    /// @brief 初始化, 清空容器
    auto init () -> void;


    /// @brief 返回容器中元素数量
    auto counts () -> std::uint16_t;


    /// @brief 检查是否存在指定的 ID 的线
    auto has (std::uint16_t _line_id) -> bool;


    /// @brief 检查是否存在指定的 ID 的线, 同时如果不存在则自动生成一个并加入容器
    /// @return true: 已经存在指定 ID 的线, false: 不存在指定 ID 的线 (已经自动创建)
    auto touch (std::uint16_t _line_id) -> bool;


    /// @brief 获取指定编号的线中的指定的点 (直接调用 Linear_Container_ct::get)
    /// @return nullptr: 指定线不存在或者指定点不存在
    auto get (std::uint16_t _line_id, std::uint16_t _no, Point_Base_st ** _pb = nullptr) -> Point_Base_st *;


    /// @brief 将点追加到指定编号的线的末尾 (直接调用 Linear_Container_ct::append)
    /// @return true: 追加成功, false: 追加失败 (可能是指定的线不存在)
    auto append (std::uint16_t _line_id, const Point_Base_st & _pb) -> bool;


    /// @brief 在指定编号的线的指定位置插入点 (直接调用 Linear_Container_ct::insert)
    /// @return true: 插入成功, false: 插入失败 (可能是指定的线不存在)
    auto insert (std::uint16_t _line_id, std::uint16_t _no, const Point_Base_st & _pb) -> bool;


    /// @brief 替换指定编号的线的指定位置的点 (直接调用 Linear_Container_ct::replace)
    /// @return true: 替换成功, false: 替换失败 (可能是指定的线不存在)
    auto replace (std::uint16_t _line_id, std::uint16_t _no, const Point_Base_st & _pb) -> bool;


    /// @brief 删除指定位置的点 (直接调用 Linear_Container_ct::remove)
    /// @return true: 删除成功, false: 删除失败 (可能是指定的线不存在)
    auto remove (std::uint16_t _line_id, std::uint16_t _no) -> bool;


    /// @brief 重载下标运算符, 这里的下标直接就是 _line_id
    /// @attention 如果 _line_id 不存在则自动生成一个并加入容器并返回其引用, 也就是说下标取元素操作总是成功的
    auto operator[] (std::uint16_t _line_id) -> Linear_Container_ct &;


    /// @brief 将线加入线库 (如果已经存在相同 ID 的线则返回 false)
    auto push (Linear_Container_ct && _line) -> bool;


    /// @brief 删除指定 ID 的线
    auto pop (std::uint16_t _line_id) -> void;


    /// @brief 更新容器内的线的ID (Linear_Container_ct::_m_line_id 会被更新, MultiLinear_Container_ct::_m_lines 也会重新映射)
    /// @return true: 更新成功, false: 更新失败 (可能是指定的 _old_line_id 不存在或者 _new_line_id 已存在)
    auto updateLineID (std::uint16_t _old_line_id, std::uint16_t _new_line_id) -> bool;


  private:
    std::unordered_map<std::uint16_t, Linear_Container_ct> _m_lines;
};

#endif
